﻿// ----------------------------------------------------------------------------
// scope_exit.h
// ----------------------------------------------------------------------------
/*
 Description :
 スコープの範囲から抜けたときに実行する処理を記述する. D言語のScope Guardと同じもの. 
 
 たとえば、ファイルハンドルのオープン/クローズであるとか、メモリの確保/解放等をあるスコープの
 範囲で行い、なおかつスコープの範囲外からでていく方法が複数ある場合（例えばreturnや例外等）
 リソースの解放コードの記述漏れによってあるパスでのみリソースがリークするような状況が発生する
 可能性がある.
 
 そのような場合に FW_SCOPE_EXIT マクロを使って、あらかじめ解放処理を記述しておく事でリソース
 の解放漏れがおきにくいコードを作成できる. 
 
 このコードはautoキーワードやラムダ式を使っているので、C++11対応のコンパイラが必要になる.
 
 ----------------------------------------------------------------
 使い方.

 スコープの範囲外に出る段階で実行したい命令を FW_SCOPE_EXIT マクロに記述する.
 マクロは一つのスコープに何個記述しても良い.
 
 {
   void* p = malloc(...);
   FW_SCOPE_EXIT(free(p));
   ...
   if(err) { return; } // pass A.
   ...
   // pass B.
 }
 
 上の場合、コードパスAを通っても、コードパスBを通ってもfree(p)は実行される.
 
 */
#pragma once
#include <fw/base/core/macros.h>

namespace fw
{
	template <typename T> class ScopeExit
	{
	public:
		T m_func;
		 ScopeExit(T func)
		: m_func(func)
		{
		}
		~ScopeExit()
		{
			m_func();
		}
	}; // class ScopeExit
	
	template <typename T> ScopeExit<T> MakeScopeExit(T func)
	{
		return ScopeExit<T>(func);
	}
	
} // namespace fw

#define FW_SCOPE_EXIT(code) auto FW_CONCAT(scopeExit, __LINE__) = fw::MakeScopeExit([&](){code;})
